home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / smail-3.1.28 / pd / pathalias / parse.y < prev    next >
Encoding:
Lex Description  |  1992-06-27  |  10.6 KB  |  546 lines

  1. %{
  2. /* Smail SCCS ID: @(#)pd/pathalias/parse.y    1.6 %G 13:53:28 */
  3. /* pathalias -- by steve bellovin, as told to peter honeyman */
  4. #ifndef lint
  5. static char    *sccsid = "@(#)parse.y    9.11 91/06/01";
  6. #endif /* lint */
  7.  
  8. #include "def.h"
  9.  
  10. /* scanner states (yylex, parse) */
  11. #define OTHER        0
  12. #define COSTING        1
  13. #define NEWLINE        2
  14. #define FILENAME    3
  15.  
  16. /* exports */
  17. long Tcount;
  18. extern void yyerror();
  19.  
  20. /* imports */
  21. extern node *addnode(), *addprivate();
  22. extern void fixprivate(), alias(), deadlink(), deletelink();
  23. extern link *addlink();
  24. #ifndef SMAIL_3
  25. extern int strcmp();
  26. #endif
  27. extern char *strsave();
  28. extern int optind;
  29. extern char *Cfile, *Netchars, **Argv;
  30. extern int Lineno, Argc;
  31. extern node *Home;        /* node for local host */
  32.  
  33. /* privates */
  34. STATIC void fixnet(), adjust();
  35. STATIC int yylex(), yywrap(), getword();
  36. static int Scanstate = NEWLINE;    /* scanner (yylex) state */
  37.  
  38. /* flags for ys_flags */
  39. #define TERMINAL 1
  40. %}
  41.  
  42. %union {
  43.     node    *y_node;
  44.     Cost    y_cost;
  45.     char    y_net;
  46.     char    *y_name;
  47.     struct {
  48.         node *ys_node;
  49.         Cost ys_cost;
  50.         short ys_flag;
  51.         char ys_net;
  52.         char ys_dir;
  53.     } y_s;
  54. }
  55.  
  56. %type <y_s>    site asite
  57. %type <y_node>    links aliases plist network nlist host nhost
  58. %type <y_node>    usite delem dlist
  59. %type <y_cost>    cost cexpr
  60.  
  61. %token <y_name>    SITE HOST STRING
  62. %token <y_cost>    COST
  63. %token <y_net>    NET
  64. %token EOL PRIVATE DEAD DELETE FILETOK ADJUST
  65.  
  66. %left    '+' '-'
  67. %left    '*' '/'
  68.  
  69. %%
  70. map    :    /* empty */
  71.     |    map        EOL
  72.     |    map links    EOL
  73.     |    map aliases    EOL
  74.     |    map network    EOL
  75.     |    map private    EOL
  76.     |    map dead    EOL
  77.     |    map delete    EOL
  78.     |    map file    EOL
  79.     |    map adjust    EOL
  80.     |    error        EOL
  81.     ;
  82.  
  83. links    : host site cost {
  84.         struct link *l;
  85.  
  86.         l = addlink($1, $2.ys_node, $3, $2.ys_net, $2.ys_dir);
  87.         if (GATEWAYED($2.ys_node))
  88.             l->l_flag |= LGATEWAY;
  89.         if ($2.ys_flag & TERMINAL)
  90.             l->l_flag |= LTERMINAL;
  91.       }            
  92.     | links ',' site cost {
  93.         struct link *l;
  94.  
  95.         l = addlink($1, $3.ys_node, $4, $3.ys_net, $3.ys_dir);
  96.         if (GATEWAYED($3.ys_node))
  97.             l->l_flag |= LGATEWAY;
  98.         if ($3.ys_flag & TERMINAL)
  99.             l->l_flag |= LTERMINAL;
  100.       }
  101.     | links ','    /* benign error */
  102.     ;
  103.  
  104. host    : HOST        {$$ = addnode($1);}
  105.     | PRIVATE    {$$ = addnode("private");}
  106.     | DEAD        {$$ = addnode("dead");}
  107.     | DELETE    {$$ = addnode("delete");}
  108.     | FILETOK    {$$ = addnode("file");}
  109.     | ADJUST    {$$ = addnode("adjust");}
  110.     ;
  111.  
  112. site    : asite {
  113.         $$ = $1;
  114.         $$.ys_net = DEFNET;
  115.         $$.ys_dir = DEFDIR;
  116.       }
  117.     | NET asite {
  118.         $$ = $2;
  119.         $$.ys_net = $1;
  120.         $$.ys_dir = LRIGHT;
  121.       }
  122.     | asite NET {
  123.         $$ = $1;
  124.         $$.ys_net = $2;
  125.         $$.ys_dir = LLEFT;
  126.       }
  127.     ;
  128.  
  129. asite    : SITE {
  130.         $$.ys_node = addnode($1);
  131.         $$.ys_flag = 0;
  132.       }
  133.     | '<' SITE '>' {
  134.         Tcount++;
  135.         $$.ys_node = addnode($2);
  136.         $$.ys_flag = TERMINAL;
  137.       }
  138.     ;
  139.  
  140. aliases    : host '=' SITE    {alias($1, addnode($3));}
  141.     | aliases ',' SITE    {alias($1, addnode($3));}
  142.     | aliases ','    /* benign error */
  143.     ;
  144.  
  145. network    : nhost '{' nlist '}' cost    {fixnet($1, $3, $5, DEFNET, DEFDIR);}
  146.     | nhost NET '{' nlist '}' cost    {fixnet($1, $4, $6, $2, LRIGHT);}
  147.     | nhost '{' nlist '}' NET cost    {fixnet($1, $3, $6, $5, LLEFT);}
  148.     ;
  149.  
  150. nhost    : '='        {$$ = 0;    /* anonymous net */}
  151.     | host '='    {$$ = $1;    /* named net */}
  152.     ;
  153.  
  154. nlist    : SITE        {$$ = addnode($1);}
  155.     | nlist ',' SITE {
  156.         node *n;
  157.  
  158.         n = addnode($3);
  159.         if (n->n_net == 0) {
  160.             n->n_net = $1;
  161.             $$ = n;
  162.         }
  163.       }
  164.     | nlist ','    /* benign error */
  165.     ;
  166.         
  167. private    : PRIVATE '{' plist '}'            /* list of privates */
  168.     | PRIVATE '{' '}'    {fixprivate();}    /* end scope of privates */
  169.     ;
  170.  
  171. plist    : SITE            {addprivate($1)->n_flag |= ISPRIVATE;}
  172.     | plist ',' SITE    {addprivate($3)->n_flag |= ISPRIVATE;}
  173.     | plist ','        /* benign error */
  174.     ;
  175.  
  176. dead    : DEAD '{' dlist '}';
  177.  
  178. dlist    : delem
  179.     | dlist ',' delem
  180.     | dlist ','        /* benign error */
  181.     ;
  182.  
  183. delem    : SITE            {deadlink(addnode($1), (node *) 0);}
  184.     | usite NET usite    {deadlink($1, $3);}
  185.     ;
  186.  
  187. usite    : SITE    {$$ = addnode($1);} ;    /* necessary unit production */
  188.  
  189. delete    : DELETE '{' dellist '}';
  190.  
  191. dellist    : delelem
  192.     | dellist ',' delelem
  193.     | dellist ','        /* benign error */
  194.     ;
  195.  
  196. delelem    : SITE {
  197.         node *n;
  198.  
  199.         n = addnode($1);
  200.         deletelink(n, (node *) 0);
  201.         n->n_flag |= ISPRIVATE;
  202.         /* reset Home if it's deleted */
  203.         if (n == Home)
  204.             Home = addnode(Home->n_name);
  205.       }
  206.     | usite NET usite    {deletelink($1, $3);}
  207.     ;
  208.  
  209. file    : FILETOK '{' {Scanstate = FILENAME;} STRING {Scanstate = OTHER;} '}' {
  210.         Lineno = 0;
  211.         Cfile = strsave($4);
  212.     }
  213.  
  214. adjust    : ADJUST '{' adjlist '}' ;
  215.  
  216. adjlist    : adjelem
  217.     | adjlist ',' adjelem
  218.     | adjlist ','        /* benign error */
  219.     ;
  220.  
  221. adjelem    : usite cost    {adjust($1, $2);} ;
  222.  
  223. cost    : {$$ = DEFCOST;    /* empty -- cost is always optional */}
  224.     | '(' {Scanstate = COSTING;} cexpr {Scanstate = OTHER;} ')'
  225.         {$$ = $3;}
  226.     ;
  227.  
  228. cexpr    : COST
  229.     | '-' cexpr      {$$ = -$2;}
  230.     | '(' cexpr ')'   {$$ = $2;}
  231.     | cexpr '+' cexpr {$$ = $1 + $3;}
  232.     | cexpr '-' cexpr {$$ = $1 - $3;}
  233.     | cexpr '*' cexpr {$$ = $1 * $3;}
  234.     | cexpr '/' cexpr {
  235.         if ($3 == 0)
  236.             yyerror("zero divisor\n");
  237.         else
  238.             $$ = $1 / $3;
  239.       }
  240.     ;
  241. %%
  242.  
  243. void
  244. #ifdef YYDEBUG
  245. /*VARARGS1*/
  246. yyerror(fmt, arg)
  247.     char *fmt, *arg;
  248. #else
  249. yyerror(s)
  250.     char *s;
  251. #endif
  252. {
  253.     /* a concession to bsd error(1) */
  254.     fprintf(stderr, "\"%s\", ", Cfile);
  255. #ifdef YYDEBUG
  256.     fprintf(stderr, "line %d: ", Lineno);
  257.     fprintf(stderr, fmt, arg);
  258.     putc('\n', stderr);
  259. #else
  260.     fprintf(stderr, "line %d: %s\n", Lineno, s);
  261. #endif
  262. }
  263.  
  264. /*
  265.  * patch in the costs of getting on/off the network.
  266.  *
  267.  * for each network member on netlist, add links:
  268.  *    network -> member    cost = 0;
  269.  *    member -> network    cost = parameter.
  270.  *
  271.  * if network and member both require gateways, assume network
  272.  * is a gateway to member (but not v.v., to avoid such travesties
  273.  * as topaz!seismo.css.gov.edu.rutgers).
  274.  *
  275.  * note that members can have varying costs to a network, by suitable
  276.  * multiple declarations.  this is a feechur, albeit a useless one.
  277.  */
  278. STATIC void
  279. fixnet(network, nlist, cost, netchar, netdir)
  280.     register node *network;
  281.     node *nlist;
  282.     Cost cost;
  283.     char netchar, netdir;
  284. {    register node *member, *nextnet;
  285.     link *l;
  286.     static int netanon = 0;
  287.     char anon[25];
  288.  
  289.     if (network == 0) {
  290.         sprintf(anon, "[unnamed net %d]", netanon++);
  291.         network = addnode(anon);
  292.     }
  293.     network->n_flag |= NNET;
  294.  
  295.     /* insert the links */
  296.     for (member = nlist ; member; member = nextnet) {
  297.  
  298.         /* network -> member, cost is 0 */
  299.         l = addlink(network, member, (Cost) 0, netchar, netdir);
  300.         if (GATEWAYED(network) && GATEWAYED(member))
  301.             l->l_flag |= LGATEWAY;
  302.  
  303.         /* member -> network, cost is parameter */
  304.         /* never ever ever crawl up from a domain*/
  305.         if (!ISADOMAIN(network))
  306.             (void) addlink(member, network, cost, netchar, netdir);
  307.  
  308.         nextnet = member->n_net;
  309.         member->n_net = 0;    /* clear for later use */
  310.     }
  311. }
  312.  
  313. /* scanner */
  314.  
  315. #define QUOTE '"'
  316. #define STR_EQ(s1, s2) (s1[2] == s2[2] && strcmp(s1, s2) == 0)
  317. #define NLRETURN() {Scanstate = NEWLINE; return EOL;}
  318.  
  319. static struct ctable {
  320.     char *cname;
  321.     Cost cval;
  322. } ctable[] = {
  323.     /* ordered by frequency of appearance in a "typical" dataset */
  324.     {"DIRECT", 200},
  325.     {"DEMAND", 300},
  326.     {"DAILY", 5000},
  327.     {"HOURLY", 500},
  328.     {"DEDICATED", 100},
  329.     {"EVENING", 2000},
  330.     {"LOCAL", 25},
  331.     {"LOW", 5},    /* baud rate, quality penalty */
  332.     {"DEAD", MILLION},
  333.     {"POLLED", 5000},
  334.     {"WEEKLY", 30000},
  335.     {"HIGH", -5},    /* baud rate, quality bonus */
  336.     {"FAST", -80},    /* high speed (>= 9.6 kbps) modem */
  337.     /* deprecated */
  338.     {"ARPA", 100},
  339.     {"DIALED", 300},
  340.     {0, 0}
  341. };
  342.  
  343. STATIC int
  344. yylex()
  345. {    static char retbuf[128];    /* for return to yacc part */
  346.     register int c;
  347.     register char *buf = retbuf;
  348.     register struct ctable *ct;
  349.     register Cost cost;
  350.     char errbuf[128];
  351.  
  352.     if (feof(stdin) && yywrap())
  353.         return EOF;
  354.  
  355.     /* count lines, skip over space and comments */
  356.     if ((c = getchar()) == EOF)
  357.         NLRETURN();
  358.     
  359. continuation:
  360.     while (c == ' ' || c == '\t')
  361.         if ((c = getchar()) == EOF)
  362.             NLRETURN();
  363.  
  364.     if (c == '#')
  365.         while ((c = getchar()) != '\n')
  366.             if (c == EOF)
  367.                 NLRETURN();
  368.  
  369.     /* scan token */
  370.     if (c == '\n') {
  371.         Lineno++;
  372.         if ((c = getchar()) != EOF) {
  373.             if (c == ' ' || c == '\t')
  374.                 goto continuation;
  375.             ungetc(c, stdin);
  376.         }
  377.         NLRETURN();
  378.     }
  379.  
  380.     switch(Scanstate) {
  381.     case COSTING:
  382.         if (isdigit(c)) {
  383.             cost = c - '0';
  384.             for (c = getchar(); isdigit(c); c = getchar())
  385.                 cost = (cost * 10) + c - '0';
  386.             ungetc(c, stdin);
  387.             yylval.y_cost = cost;
  388.             return COST;
  389.         }
  390.  
  391.         if (getword(buf, c) == 0) {
  392.             for (ct = ctable; ct->cname; ct++)
  393.                 if (STR_EQ(buf, ct->cname)) {
  394.                     yylval.y_cost = ct->cval;
  395.                     return COST;
  396.                 }
  397.             sprintf(errbuf, "unknown cost (%s), using default", buf);
  398.             yyerror(errbuf);
  399.             yylval.y_cost = DEFCOST;
  400.             return COST;
  401.         }
  402.  
  403.         return c;    /* pass the buck */
  404.  
  405.     case NEWLINE:
  406.         Scanstate = OTHER;
  407.         if (getword(buf, c) != 0)
  408.             return c;
  409.         /*
  410.          * special purpose tokens.
  411.          *
  412.          * the "switch" serves the dual-purpose of recognizing
  413.          * unquoted tokens only.
  414.          */
  415.         switch(c) {
  416.         case 'p':
  417.             if (STR_EQ(buf, "private"))
  418.                 return PRIVATE;
  419.             break;
  420.         case 'd':
  421.             if (STR_EQ(buf, "dead"))
  422.                 return DEAD;
  423.             if (STR_EQ(buf, "delete"))
  424.                 return DELETE;
  425.             break;
  426.         case 'f':
  427.             if (STR_EQ(buf, "file"))
  428.                 return FILETOK;
  429.             break;
  430.         case 'a':
  431.             if (STR_EQ(buf, "adjust"))
  432.                 return ADJUST;
  433.             break;
  434.         }
  435.  
  436.         yylval.y_name = buf;
  437.         return HOST;
  438.  
  439.     case FILENAME:
  440.         while (c != EOF && isprint(c)) {
  441.             if (c == ' ' || c == '\t' || c == '\n' || c == '}')
  442.                 break;
  443.             *buf++ = c;
  444.             c = getchar();
  445.         }
  446.         if (c != EOF)
  447.             ungetc(c, stdin);
  448.         *buf = 0;
  449.         yylval.y_name = retbuf;
  450.         return STRING;
  451.     }
  452.  
  453.     if (getword(buf, c) == 0) {
  454.         yylval.y_name = buf;
  455.         return SITE;
  456.     }
  457.  
  458.     if (index(Netchars, c)) {
  459.         yylval.y_net = c;
  460.         return NET;
  461.     }
  462.  
  463.     return c;
  464. }
  465.  
  466. /*
  467.  * fill str with the next word in [0-9A-Za-z][-._0-9A-Za-z]+ or a quoted
  468.  * string that contains no newline.  return -1 on failure or EOF, 0 o.w.
  469.  */ 
  470. STATIC int
  471. getword(str, c)
  472.     register char *str;
  473.     register int c;
  474. {
  475.     if (c == QUOTE) {
  476.         while ((c = getchar()) != QUOTE) {
  477.             if (c == '\n') {
  478.                 yyerror("newline in quoted string\n");
  479.                 ungetc(c, stdin);
  480.                 return -1;
  481.             }
  482.             if (c == EOF) {
  483.                 yyerror("EOF in quoted string\n");
  484.                 return -1;
  485.             }
  486.             *str++ = c;
  487.         }
  488.         *str = 0;
  489.         return 0;
  490.     }
  491.  
  492.     /* host name must start with alphanumeric or `.' */
  493.     if (!isalnum(c) && c != '.')
  494.         return -1;
  495.  
  496. yymore:
  497.     do {
  498.         *str++ = c;
  499.         c = getchar();
  500.     } while (isalnum(c) || c == '.' || c == '_');
  501.  
  502.     if (c == '-' && Scanstate != COSTING)
  503.         goto yymore;
  504.  
  505.     ungetc(c, stdin);
  506.     *str = 0;
  507.     return 0;
  508. }
  509.  
  510. STATIC int
  511. yywrap()
  512. {    char errbuf[100];
  513.  
  514.     fixprivate();    /* munge private host definitions */
  515.     Lineno = 1;
  516.     while (optind < Argc) {
  517.         if (freopen((Cfile = Argv[optind++]), "r", stdin) != 0)
  518.             return 0;
  519.         sprintf(errbuf, "%s: %s", Argv[0], Cfile);
  520.         perror(errbuf);
  521.     }
  522.     freopen("/dev/null", "r", stdin);
  523.     return -1;
  524. }
  525.  
  526. STATIC void
  527. adjust(n, cost)
  528.     node *n;
  529.     Cost cost;
  530. {    link *l;
  531.  
  532.     n->n_cost += cost;    /* cumulative */
  533.  
  534.     /* hit existing links */
  535.     for (l = n->n_link; l; l = l->l_next) {
  536.         if ((l->l_cost += cost) < 0) {
  537.             char buf[100];
  538.  
  539.             l->l_flag |= LDEAD;
  540.             sprintf(buf, "link to %s deleted with negative cost",
  541.                             l->l_to->n_name);
  542.             yyerror(buf);
  543.         }
  544.     }
  545. }
  546.